home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WPrefs.app / editmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-29  |  14.4 KB  |  670 lines

  1. /* editmenu.c - editable menus
  2.  * 
  3.  *  WPrefs - Window Maker Preferences Program
  4.  * 
  5.  *  Copyright (c) 1999 Alfredo K. Kojima
  6.  * 
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  20.  *  USA.
  21.  */
  22.  
  23. #if 0
  24. #include <WINGsP.h>
  25. #include <WUtil.h>
  26. #include <stdlib.h>
  27. #include <assert.h>
  28. #include <ctype.h>
  29.  
  30. #include "editmenu.h"
  31.  
  32. typedef struct W_EditMenuItem {
  33.     W_Class widgetClass;
  34.     WMView *view;
  35.  
  36.     struct W_EditMenu *menu;
  37.  
  38.     char *label;
  39.  
  40.     WMTextField *textField;
  41.  
  42.     struct W_EditMenu *submenu;           /* if it's a cascade, NULL otherwise */
  43. } EditMenuItem;
  44.  
  45.  
  46. typedef struct W_EditMenu {
  47.     W_Class widgetClass;
  48.     WMView *view;
  49.  
  50.     struct W_EditMenu *parent;
  51.  
  52.     char *label;
  53.  
  54.     int itemCount;
  55.     int itemsAlloced;
  56.     struct W_EditMenuItem **items;
  57.  
  58.     int titleHeight;
  59.     int itemHeight;
  60.  
  61.     struct W_EditMenu *next;
  62.     struct W_EditMenu *prev;
  63.  
  64.     /* item dragging */
  65.     int draggedItem;
  66.     int dragX, dragY;
  67. } EditMenu;
  68.  
  69.  
  70.  
  71. /******************** WEditMenuItem ********************/
  72.  
  73. static void destroyEditMenuItem(WEditMenuItem *iPtr);
  74. static void paintEditMenuItem(WEditMenuItem *iPtr);
  75.  
  76. static void handleItemEvents(XEvent *event, void *data);
  77. static void handleItemActionEvents(XEvent *event, void *data);
  78.  
  79.  
  80. static W_ViewProcedureTable WEditMenuItemViewProcedures = {
  81.     NULL,
  82.     NULL,
  83.     NULL
  84. };
  85.  
  86.  
  87. static W_Class EditMenuItemClass = 0;
  88.  
  89.  
  90. W_Class
  91. InitEditMenuItem(WMScreen *scr)
  92. {
  93.     /* register our widget with WINGs and get our widget class ID */
  94.     if (!EditMenuItemClass) {
  95.     EditMenuItemClass = W_RegisterUserWidget(&WEditMenuItemViewProcedures);
  96.     }
  97.  
  98.     return EditMenuItemClass;
  99. }
  100.  
  101.  
  102. WEditMenuItem*
  103. WCreateEditMenuItem(WMWidget *parent, char *title)
  104. {
  105.     WEditMenuItem *iPtr;
  106.  
  107.     if (!EditMenuItemClass)
  108.     InitEditMenuItem(WMWidgetScreen(parent));
  109.  
  110.  
  111.     iPtr = wmalloc(sizeof(WEditMenuItem));
  112.  
  113.     memset(iPtr, 0, sizeof(WEditMenuItem));
  114.  
  115.     iPtr->widgetClass = EditMenuItemClass;
  116.     
  117.     iPtr->view = W_CreateView(W_VIEW(parent));
  118.     if (!iPtr->view) {
  119.     free(iPtr);
  120.     return NULL;
  121.     }
  122.     iPtr->view->self = iPtr;
  123.  
  124.     iPtr->label = wstrdup(title);
  125.  
  126.     WMCreateEventHandler(iPtr->view, ExposureMask|StructureNotifyMask,
  127.              handleItemEvents, iPtr);
  128.  
  129.     WMCreateEventHandler(iPtr->view, ButtonPressMask, handleItemActionEvents,
  130.              iPtr);
  131.  
  132.     return iPtr;
  133. }
  134.  
  135.  
  136.  
  137. static void
  138. paintEditMenuItem(WEditMenuItem *iPtr)
  139. {
  140.     WMScreen *scr = WMWidgetScreen(iPtr);
  141.     WMColor *black = scr->black;
  142.     Window win = W_VIEW(iPtr)->window;
  143.     int w = W_VIEW(iPtr)->size.width;
  144.     int h = WMFontHeight(scr->normalFont) + 6;
  145.  
  146.     if (!iPtr->view->flags.realized)
  147.     return;
  148.  
  149.     XClearWindow(scr->display, win);
  150.  
  151.     W_DrawRelief(scr, win, 0, 0, w+1, h, WRRaised);
  152.  
  153.     WMDrawString(scr, win, WMColorGC(black), scr->normalFont, 5, 3, iPtr->label,
  154.          strlen(iPtr->label));
  155. }
  156.  
  157.  
  158. static void
  159. handleItemEvents(XEvent *event, void *data)
  160. {
  161.     WEditMenuItem *iPtr = (WEditMenuItem*)data;
  162.  
  163.  
  164.     switch (event->type) {    
  165.      case Expose:
  166.     if (event->xexpose.count!=0)
  167.         break;
  168.     paintEditMenuItem(iPtr);
  169.     break;
  170.     
  171.      case DestroyNotify:
  172.     destroyEditMenuItem(iPtr);
  173.     break;
  174.     
  175.     }
  176. }
  177.  
  178.  
  179. static void
  180. handleItemActionEvents(XEvent *event, void *data)
  181. {
  182.     WEditMenuItem *iPtr = (WEditMenuItem*)data;
  183.  
  184.     switch (event->type) {
  185.      case ButtonPress:
  186.     break;
  187.     }
  188. }
  189.  
  190.  
  191.  
  192. static void
  193. destroyEditMenuItem(WEditMenuItem *iPtr)
  194. {
  195.     if (iPtr->label)
  196.     free(iPtr->label);
  197.  
  198.     free(iPtr);
  199. }
  200.  
  201.  
  202.  
  203. /******************** WEditMenu *******************/
  204.  
  205.  
  206. static WEditMenu *EditMenuList = NULL;
  207.  
  208. static void destroyEditMenu(WEditMenu *mPtr);
  209. static void paintEditMenu(WEditMenu *mPtr, int y);
  210.  
  211. static void updateMenuContents(WEditMenu *mPtr);
  212.  
  213. static void handleEvents(XEvent *event, void *data);
  214. static void handleActionEvents(XEvent *event, void *data);
  215.  
  216. static void handleItemDrag(XEvent *event, void *data);
  217.  
  218.  
  219. static W_ViewProcedureTable WEditMenuViewProcedures = {
  220.     NULL,
  221.     NULL,
  222.     NULL
  223. };
  224.  
  225.  
  226. static W_Class EditMenuClass = 0;
  227.  
  228.  
  229. W_Class
  230. InitEditMenu(WMScreen *scr)
  231. {
  232.     /* register our widget with WINGs and get our widget class ID */
  233.     if (!EditMenuClass) {
  234.  
  235.     EditMenuClass = W_RegisterUserWidget(&WEditMenuViewProcedures);
  236.     }
  237.  
  238.     return EditMenuClass;
  239. }
  240.  
  241.  
  242.  
  243. typedef struct {
  244.     int flags;
  245.     int window_style;
  246.     int window_level;
  247.     int reserved;
  248.     Pixmap miniaturize_pixmap;         /* pixmap for miniaturize button */
  249.     Pixmap close_pixmap;               /* pixmap for close button */
  250.     Pixmap miniaturize_mask;           /* miniaturize pixmap mask */
  251.     Pixmap close_mask;                 /* close pixmap mask */
  252.     int extra_flags;
  253. } GNUstepWMAttributes;
  254.  
  255.  
  256. #define GSWindowStyleAttr       (1<<0)
  257. #define GSWindowLevelAttr       (1<<1)
  258.  
  259.  
  260. static void
  261. writeGNUstepWMAttr(WMScreen *scr, Window window, GNUstepWMAttributes *attr)
  262. {
  263.     unsigned long data[9];
  264.         
  265.     /* handle idiot compilers where array of CARD32 != struct of CARD32 */
  266.     data[0] = attr->flags;
  267.     data[1] = attr->window_style;
  268.     data[2] = attr->window_level;
  269.     data[3] = 0;                       /* reserved */
  270.     /* The X protocol says XIDs are 32bit */
  271.     data[4] = attr->miniaturize_pixmap;
  272.     data[5] = attr->close_pixmap;
  273.     data[6] = attr->miniaturize_mask;
  274.     data[7] = attr->close_mask;
  275.     data[8] = attr->extra_flags;
  276.     XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
  277.                     32, PropModeReplace,  (unsigned char *)data, 9);
  278. }
  279.  
  280.  
  281. static void
  282. realizeObserver(void *self, WMNotification *not)
  283. {
  284.     WEditMenu *menu = (WEditMenu*)self;
  285.     GNUstepWMAttributes attribs;
  286.     
  287.     memset(&attribs, 0, sizeof(GNUstepWMAttributes));
  288.     attribs.flags = GSWindowStyleAttr|GSWindowLevelAttr;
  289.     attribs.window_style = WMBorderlessWindowMask;
  290.     attribs.window_level = WMSubmenuWindowLevel;
  291.  
  292.     writeGNUstepWMAttr(WMWidgetScreen(menu), menu->view->window, &attribs);
  293. }
  294.  
  295.  
  296. WEditMenu*
  297. WCreateEditMenu(WMScreen *scr, char *title)
  298. {
  299.     WEditMenu *mPtr;
  300.  
  301.     if (!EditMenuClass)
  302.     InitEditMenu(scr);
  303.  
  304.  
  305.     mPtr = wmalloc(sizeof(WEditMenu));
  306.  
  307.     memset(mPtr, 0, sizeof(WEditMenu));
  308.  
  309.     mPtr->widgetClass = EditMenuClass;
  310.  
  311.     mPtr->view = W_CreateTopView(scr);
  312.     if (!mPtr->view) {
  313.     free(mPtr);
  314.     return NULL;
  315.     }
  316.     mPtr->view->self = mPtr;
  317.  
  318.     WMAddNotificationObserver(realizeObserver, mPtr,
  319.                               WMViewRealizedNotification, mPtr->view);
  320.  
  321.     W_SetViewBackgroundColor(mPtr->view, mPtr->view->screen->darkGray);
  322.  
  323.     mPtr->label = wstrdup(title);
  324.  
  325.     mPtr->itemsAlloced = 10;
  326.     mPtr->items = wmalloc(sizeof(WEditMenuItem*)*mPtr->itemsAlloced);
  327.  
  328.     WMCreateEventHandler(mPtr->view, ExposureMask|StructureNotifyMask,
  329.              handleEvents, mPtr);
  330.  
  331.     WMCreateEventHandler(mPtr->view, ButtonPressMask,handleActionEvents, mPtr);
  332.  
  333.     updateMenuContents(mPtr);
  334.  
  335.  
  336.     mPtr->itemHeight = WMFontHeight(scr->normalFont) + 6;
  337.     mPtr->titleHeight = WMFontHeight(scr->boldFont) + 8;
  338.  
  339.     mPtr->draggedItem = -1;
  340.  
  341.     mPtr->next = EditMenuList;
  342.     if (EditMenuList)
  343.     EditMenuList->prev = mPtr;
  344.     EditMenuList = mPtr;
  345.  
  346.     return mPtr;
  347. }
  348.  
  349.  
  350. WEditMenuItem*
  351. WInsertMenuItemWithTitle(WEditMenu *mPtr, char *title, int index)
  352. {
  353.     WEditMenuItem *item;
  354.  
  355.     item = WCreateEditMenuItem(mPtr, title);
  356.     item->menu = mPtr;
  357.  
  358.     WMCreateEventHandler(item->view, ButtonPressMask|ButtonReleaseMask
  359.              |Button1MotionMask, handleItemDrag, item);
  360.  
  361.     WMMapWidget(item);
  362.  
  363.     if (index < 0)
  364.     index = 0;
  365.     else if (index > mPtr->itemCount)
  366.     index = mPtr->itemCount;
  367.  
  368.     if (mPtr->itemCount == mPtr->itemsAlloced) {
  369.     WEditMenuItem **newList;
  370.  
  371.     newList = wmalloc(sizeof(WEditMenuItem*)*(mPtr->itemsAlloced+10));
  372.     memset(newList, 0, sizeof(WEditMenuItem*)*(mPtr->itemsAlloced+10));
  373.  
  374.     memcpy(newList, mPtr->items, mPtr->itemsAlloced*sizeof(WEditMenuItem*));
  375.  
  376.     mPtr->itemsAlloced += 10;
  377.  
  378.     free(mPtr->items);
  379.  
  380.     mPtr->items = newList;
  381.     }
  382.  
  383.     if (index < mPtr->itemCount) {
  384.     memmove(&mPtr->items[index+1], &mPtr->items[index], 
  385.         sizeof(WEditMenuItem*));
  386.     mPtr->items[index] = item;
  387.     mPtr->itemCount++;
  388.     } else {
  389.     mPtr->items[mPtr->itemCount++] = item;
  390.     }
  391.  
  392.     updateMenuContents(mPtr);
  393.  
  394.     return item;
  395. }
  396.  
  397.  
  398. void
  399. WSetMenuSubmenu(WEditMenu *mPtr, WEditMenu *submenu, WEditMenuItem *item)
  400. {
  401.     item->submenu = submenu;
  402.     submenu->parent = mPtr;
  403.  
  404.     paintEditMenuItem(item);
  405. }
  406.  
  407.  
  408. void
  409. WRemoveMenuItem(WEditMenu *mPtr, WEditMenuItem *item)
  410. {
  411.     
  412. }
  413.  
  414.  
  415. static void
  416. updateMenuContents(WEditMenu *mPtr)
  417. {
  418.     WMScreen *scr = WMWidgetScreen(mPtr);
  419.     int i;
  420.     int newW, newH;
  421.     int w;
  422.     int iheight = mPtr->itemHeight;
  423.  
  424.     newW = WMWidthOfString(scr->boldFont, mPtr->label,
  425.                strlen(mPtr->label)) + 12 + iheight;
  426.  
  427.     newH = mPtr->titleHeight;
  428.  
  429.     for (i = 0; i < mPtr->itemCount; i++) {
  430.     w = WMWidthOfString(scr->normalFont, mPtr->items[i]->label,
  431.                 strlen(mPtr->items[i]->label)) + 5;
  432.     if (w > newW)
  433.         newW = w;
  434.  
  435.     W_MoveView(mPtr->items[i]->view, 0, newH);
  436.     newH += iheight;
  437.     }
  438.  
  439.     newH--;
  440.  
  441.     W_ResizeView(mPtr->view, newW, newH);
  442.  
  443.     for (i = 0; i < mPtr->itemCount; i++) {
  444.     W_ResizeView(mPtr->items[i]->view, newW, iheight);
  445.     }
  446.  
  447.     paintEditMenu(mPtr, -1);
  448. }
  449.  
  450.  
  451. static void
  452. paintMenuTitle(WEditMenu *mPtr)
  453. {
  454.     WMScreen *scr = WMWidgetScreen(mPtr);
  455.     WMColor *black = scr->black;
  456.     WMColor *white = scr->white;
  457.     Window win = W_VIEW(mPtr)->window;
  458.     int w = W_VIEW(mPtr)->size.width;
  459.     int h = mPtr->titleHeight;
  460.  
  461.     XFillRectangle(scr->display, win, WMColorGC(black), 0, 0, w, h);
  462.  
  463.     W_DrawRelief(scr, win, 0, 0, w+1, h, WRRaised);
  464.  
  465.     WMDrawString(scr, win, WMColorGC(white), scr->boldFont, 5, 4, mPtr->label,
  466.          strlen(mPtr->label));
  467. }
  468.  
  469.  
  470. static void
  471. paintEditMenu(WEditMenu *mPtr, int y)
  472. {
  473.     if (!mPtr->view->flags.realized)
  474.     return;
  475.  
  476.     if (y < mPtr->titleHeight || y < 0)
  477.     paintMenuTitle(mPtr);
  478. }
  479.  
  480.  
  481.  
  482. static void
  483. handleEvents(XEvent *event, void *data)
  484. {
  485.     WEditMenu *mPtr = (WEditMenu*)data;
  486.  
  487.  
  488.     switch (event->type) {    
  489.      case Expose:
  490.     paintEditMenu(mPtr, event->xexpose.y);
  491.     break;
  492.     
  493.      case DestroyNotify:
  494.     destroyEditMenu(mPtr);
  495.     break;
  496.     
  497.     }
  498. }
  499.  
  500.  
  501.  
  502.  
  503. static void
  504. handleActionEvents(XEvent *event, void *data)
  505. {
  506.     WEditMenu *mPtr = (WEditMenu*)data;
  507.  
  508.     switch (event->type) {
  509.      case ButtonPress:
  510.     break;
  511.     }
  512. }
  513.  
  514.  
  515. static void
  516. editItemLabel(WEditMenuItem *iPtr)
  517. {
  518.     WMTextField *tPtr;
  519.  
  520.     tPtr = WMCreateTextField(iPtr);
  521.     WMResizeWidget(tPtr, iPtr->view->size.width - 20, 
  522.            iPtr->view->size.height - 3);
  523.     WMMoveWidget(tPtr, 4, 1);
  524.     WMSetTextFieldBeveled(tPtr, False);
  525.     WMMapWidget(tPtr);
  526.  
  527.     WMRealizeWidget(tPtr);
  528.  
  529.     iPtr->textField = tPtr;
  530. }
  531.  
  532.  
  533. static void
  534. handleItemDrag(XEvent *event, void *data)
  535. {
  536.     WEditMenuItem *iPtr = (WEditMenuItem*)data;
  537.     WEditMenu *mPtr = iPtr->menu;
  538.     WMScreen *scr = WMWidgetScreen(mPtr);
  539.     Bool done = False;
  540.     int y;
  541.     int i;
  542.     int newIdx, oldIdx;
  543.     int newY;
  544.  
  545.     switch (event->type) {
  546.      case ButtonPress:
  547.     if (WMIsDoubleClick(event)) {
  548.  
  549.         editItemLabel(iPtr);
  550.  
  551.     } else if (event->xbutton.button == Button1) {
  552.         mPtr->draggedItem = 1;
  553.         mPtr->dragX = event->xbutton.x;
  554.         mPtr->dragY = event->xbutton.y;
  555.     }
  556.     return;
  557.      case ButtonRelease:
  558.     if (event->xbutton.button == Button1) {
  559.         mPtr->draggedItem = -1;
  560.     }
  561.     return;
  562.      case MotionNotify:
  563.     if (mPtr->draggedItem >= 0) {
  564.         if (abs(event->xmotion.y - mPtr->dragY) > 3
  565.         || abs(event->xmotion.x - mPtr->dragX) > 3) {
  566.         mPtr->draggedItem = -1;
  567.         } else {
  568.         return;
  569.         }
  570.     } else {
  571.         return;
  572.     }
  573.     break;
  574.      default:
  575.     return;
  576.     }
  577.  
  578.     XRaiseWindow(scr->display, iPtr->view->window);
  579.  
  580.     XGrabPointer(scr->display, mPtr->view->window, False,
  581.          PointerMotionMask|ButtonReleaseMask|ButtonPressMask
  582.          |ButtonPressMask,
  583.          GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
  584.  
  585.     y = iPtr->view->pos.y;
  586.  
  587.     while (!done) {
  588.     XEvent ev;
  589.  
  590.     WMMaskEvent(scr->display, ButtonReleaseMask|PointerMotionMask
  591.             |ExposureMask, &ev);
  592.  
  593.     switch (ev.type) {
  594.      case ButtonRelease:
  595.         if (ev.xbutton.button == Button1)
  596.         done = True;
  597.         break;
  598.  
  599.      case MotionNotify:
  600.         y = ev.xbutton.y - mPtr->dragY;
  601.  
  602.         if (y < mPtr->titleHeight)
  603.         y = mPtr->titleHeight;
  604.         else if (y > mPtr->view->size.height - mPtr->itemHeight + 1)
  605.         y = mPtr->view->size.height - mPtr->itemHeight + 1;
  606.  
  607.         W_MoveView(iPtr->view, 0, y);
  608.         break;
  609.  
  610.      default:
  611.         WMHandleEvent(&ev);
  612.         break;
  613.     }
  614.     }
  615.     XUngrabPointer(scr->display, CurrentTime);
  616.  
  617.     for (oldIdx = 0; oldIdx < mPtr->itemCount; oldIdx++) {
  618.     if (mPtr->items[oldIdx] == iPtr) {
  619.         break;
  620.     }
  621.     }
  622.     assert(oldIdx < mPtr->itemCount);
  623.  
  624.     newIdx = (y - mPtr->titleHeight + mPtr->itemHeight/2) / mPtr->itemHeight;
  625.  
  626.     if (newIdx < 0)
  627.     newIdx = 0;
  628.     else if (newIdx >= mPtr->itemCount)
  629.     newIdx = mPtr->itemCount - 1;
  630.  
  631.     newY = mPtr->titleHeight + newIdx * mPtr->itemHeight;
  632.     for (i = 0; i <= 15; i++) {
  633.     W_MoveView(iPtr->view, 0, ((newY*i)/15 + (y - (y*i)/15)));
  634.     XFlush(scr->display);
  635.     }
  636.  
  637.     if (oldIdx != newIdx) {
  638.     WEditMenuItem *item;
  639.  
  640.     item = mPtr->items[oldIdx];
  641.     mPtr->items[oldIdx] = mPtr->items[newIdx];
  642.     mPtr->items[newIdx] = item;
  643.  
  644.     updateMenuContents(mPtr);
  645.     }
  646. }
  647.  
  648.  
  649. static void
  650. destroyEditMenu(WEditMenu *mPtr)
  651. {
  652.     WMRemoveNotificationObserver(mPtr);
  653.  
  654.     if (mPtr->next)
  655.     mPtr->next->prev = mPtr->prev;
  656.     if (mPtr->prev)
  657.     mPtr->prev->next = mPtr->next;
  658.     if (EditMenuList == mPtr)
  659.     EditMenuList = mPtr->next;
  660.  
  661.     if (mPtr->label)
  662.     free(mPtr->label);
  663.  
  664.     if (mPtr->items)
  665.     free(mPtr->items);
  666.  
  667.     free(mPtr);
  668. }
  669. #endif
  670.